package emu.grasscutter.game.props;

import it.unimi.dsi.fastutil.ints.*;
import java.util.stream.Stream;
import lombok.Getter;

public enum PlayerProperty {
    PROP_NONE(0),
    PROP_EXP(1001, 0),
    PROP_BREAK_LEVEL(1002),
    PROP_SATIATION_VAL(1003),
    PROP_SATIATION_PENALTY_TIME(1004),
    PROP_LEVEL(4001, 0, 90),
    PROP_LAST_CHANGE_AVATAR_TIME(10001),
    PROP_MAX_SPRING_VOLUME(
            10002, 0, 8_500_000), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
    PROP_CUR_SPRING_VOLUME(
            10003, true), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
    PROP_IS_SPRING_AUTO_USE(
            10004, 0, 1), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
    PROP_SPRING_AUTO_USE_PERCENT(10005, 0, 100), // Auto HP recovery percentage [0, 100]
    PROP_IS_FLYABLE(
            10006, 0, 1), // Are you in a state that disables your flying ability? e.g. new player [0, 1]
    PROP_IS_WEATHER_LOCKED(10007, 0, 1), // Weather will not change in this state.
    PROP_IS_GAME_TIME_LOCKED(10008, 0, 1), // Game time will not move in this state.
    PROP_IS_TRANSFERABLE(10009, 0, 1),
    PROP_MAX_STAMINA(10010, 0, 24_000), // Maximum stamina of the player (0 - 24000)
    PROP_CUR_PERSIST_STAMINA(10011, true), // Used stamina of the player (0 - PROP_MAX_STAMINA)
    PROP_CUR_TEMPORARY_STAMINA(10012),
    PROP_PLAYER_LEVEL(10013, 1, 60), // Player level [1, 60]
    PROP_PLAYER_EXP(10014, 0), // Player EXP (0, +inf)
    PROP_PLAYER_HCOIN(10015), // Primogem (-inf, +inf)
    // It is known that Mihoyo will make Primogem negative in the cases that a player spends
    //   his gems and then got a money refund, so negative is allowed.
    PROP_PLAYER_SCOIN(10016, 0), // Mora [0, +inf)
    PROP_PLAYER_MP_SETTING_TYPE(
            10017, 0, 2), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
    PROP_IS_MP_MODE_AVAILABLE(10018, 0, 1), // 0 if in quest or something that disables MP [0, 1]
    PROP_PLAYER_WORLD_LEVEL(10019, 0, 8), // [0, 8]
    PROP_PLAYER_RESIN(
            10020, 0, 2000), // Original Resin [0, 2000] - note that values above 160 require refills
    PROP_PLAYER_WAIT_SUB_HCOIN(10022),
    PROP_PLAYER_WAIT_SUB_SCOIN(10023),
    PROP_IS_ONLY_MP_WITH_PS_PLAYER(10024, 0, 1), // Is only MP with PlayStation players? [0, 1]
    PROP_PLAYER_MCOIN(10025), // Genesis Crystal (-inf, +inf) see 10015
    PROP_PLAYER_WAIT_SUB_MCOIN(10026),
    PROP_PLAYER_LEGENDARY_KEY(10027, 0), // Amount of story keys [0, 3]
    PROP_IS_HAS_FIRST_SHARE(10028),
    PROP_PLAYER_FORGE_POINT(10029, 0, 300_000),
    PROP_CUR_CLIMATE_METER(10035),
    PROP_CUR_CLIMATE_TYPE(10036),
    PROP_CUR_CLIMATE_AREA_ID(10037),
    PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE(10038),
    PROP_PLAYER_WORLD_LEVEL_LIMIT(10039, 0, 8), // [0, 8] World level limit, up to 8.
    PROP_PLAYER_WORLD_LEVEL_ADJUST_CD(10040), // Time until world level can be increased/decreased.
    PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM(10041), // Amount of remaining quests for another story key.
    PROP_PLAYER_HOME_COIN(10042, 0), // Realm currency [0, +inf)
    PROP_PLAYER_WAIT_SUB_HOME_COIN(10043),
    PROP_IS_AUTO_UNLOCK_SPECIFIC_EQUIP(10044), // New; unknown/un-used.
    PROP_PLAYER_GCG_COIN(10045), // New; unknown/un-used.
    PROP_PLAYER_WAIT_SUB_GCG_COIN(10046), // New; unknown/un-used.
    PROP_PLAYER_ONLINE_TIME(10047), // New; unknown/un-used.
    PROP_PLAYER_CAN_DIVE(10048, 0, 1), // Can the player dive? [0, 1]
    PROP_DIVE_MAX_STAMINA(
            10049, 0, 10000), // The maximum stamina of the player when diving. [0, 10000]
    PROP_DIVE_CUR_STAMINA(
            10050, 0, 10000); // The current stamina of the player when diving. [0, 10000]

    private static final int inf = Integer.MAX_VALUE; // Maybe this should be something else?
    private static final Int2ObjectMap<PlayerProperty> map = new Int2ObjectOpenHashMap<>();

    static {
        Stream.of(values()).forEach(e -> map.put(e.getId(), e));
    }

    @Getter private final int id, min, max;
    @Getter private final boolean dynamicRange;

    PlayerProperty(int id, int min, int max, boolean dynamicRange) {
        this.id = id;
        this.min = min;
        this.max = max;
        this.dynamicRange = dynamicRange;
    }

    PlayerProperty(int id, int min) {
        this(id, min, inf, false);
    }

    PlayerProperty(int id, int min, int max) {
        this(id, min, max, false);
    }

    PlayerProperty(int id) {
        this(id, Integer.MIN_VALUE, inf, false);
    }

    PlayerProperty(int id, boolean dynamicRange) {
        this(id, Integer.MIN_VALUE, inf, dynamicRange);
    }

    public static PlayerProperty getPropById(int value) {
        return map.getOrDefault(value, null);
    }
}
